package cn.accjiyun.ca.common.dao;

import cn.accjiyun.ca.common.entity.PageModel;
import cn.accjiyun.ca.common.entity.QueryEntity;
import cn.accjiyun.ca.common.utils.GenericsUtils;
import org.hibernate.Criteria;
import org.hibernate.Query;
import org.hibernate.Session;
import org.hibernate.SessionFactory;
import org.hibernate.criterion.Disjunction;
import org.hibernate.criterion.Order;
import org.hibernate.criterion.Restrictions;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.transaction.annotation.Propagation;
import org.springframework.transaction.annotation.Transactional;

import java.io.Serializable;
import java.sql.Timestamp;
import java.util.Iterator;
import java.util.List;
import java.util.Map;

/**
 * Created by jiyun on 2017/3/30.
 */
public class DaoSupport<T> implements BaseDao<T> {
    // 泛型的类型
    protected Class<T> entityClass = GenericsUtils.getGenericType(this.getClass());

    @Autowired
    @Qualifier("sessionFactory")
    private SessionFactory sessionFactory;

    protected Session getSession() {
        return sessionFactory.getCurrentSession();
    }

    protected Criteria getCriteria() {
        return getSession().createCriteria(entityClass);
    }


    /**
     * 删除实体对象
     *
     * @param ids
     */
    @Override
    public void delete(Serializable... ids) {
        for (Serializable id : ids) {
            T t = getSession().load(this.entityClass, id);
            getSession().delete(t);
        }
    }

    /**
     * 利用get()方法加载对象，获取对象的详细信息
     *
     * @param entityId 实体对象ID
     * @return 实体对象
     */
    @Transactional(propagation = Propagation.NOT_SUPPORTED, readOnly = true)
    public T get(Serializable entityId) {
        return getSession().get(this.entityClass, entityId);
    }

    /**
     * 利用load()方法加载对象，获取对象的详细信息
     *
     * @param entityId 实体对象ID
     * @return 实体对象
     */
    @Transactional(propagation = Propagation.NOT_SUPPORTED, readOnly = true)
    public T load(Serializable entityId) {
        return getSession().load(this.entityClass, entityId);
    }

    /**
     * 利用hql语句查找单条信息
     *
     * @param hql
     * @param queryParams
     * @return
     */
    @Override
    @Transactional(propagation = Propagation.NOT_SUPPORTED, readOnly = true)
    public Object uniqueResult(final String hql, final Object[] queryParams) {
        Query query = getSession().createQuery(hql);
        setQueryParams(query, queryParams);//设置查询参数
        return query.uniqueResult();
    }

    /**
     * 获取指定对象的信息条数
     */
    @Transactional(propagation = Propagation.NOT_SUPPORTED, readOnly = true)
    public long getCount() {
        String hql = "select count(*) from " + GenericsUtils.getGenericName(this.entityClass);
        return (Long) uniqueResult(hql, null);
    }

    /**
     * 利用save()方法保存对象的详细信息
     */
    @Override
    public void save(Object obj) {
        getSession().save(obj);
    }

    @Override
    public void saveOrUpdate(Object obj) {
        getSession().saveOrUpdate(obj);
    }

    /**
     * 利用update()方法修改对象的详细信息
     */
    @Override
    public void update(Object obj) {
        getSession().update(obj);
    }

    @Transactional(propagation = Propagation.NOT_SUPPORTED, readOnly = true)
    public PageModel<T> find(final int pageNo, int pageSize) {
        return find(null, null, null, pageNo, pageSize);
    }

    @Transactional(propagation = Propagation.NOT_SUPPORTED, readOnly = true)
    public PageModel<T> find(int pageNo, int pageSize,
                             Map<String, String> orderby) {
        return find(null, null, orderby, pageNo, pageSize);
    }

    @Transactional(propagation = Propagation.NOT_SUPPORTED, readOnly = true)
    public PageModel<T> find(int pageNo, int pageSize, String where,
                             Object[] queryParams) {
        return find(where, queryParams, null, pageNo, pageSize);
    }

    /**
     * 分页查询
     *
     * @param where       查询条件
     * @param queryParams hql参数值
     * @param orderby     排序
     * @param pageNo      第几页
     * @param pageSize    返回记录数量
     *                    return PageModel
     */
    @Transactional(propagation = Propagation.NOT_SUPPORTED, readOnly = true)
    public PageModel<T> find(final String where, final Object[] queryParams,
                             final Map<String, String> orderby, final int pageNo,
                             final int pageSize) {
        final PageModel<T> pageModel = new PageModel<>();//实例化分页对象
        pageModel.setPageNo(pageNo);//设置当前页数
        pageModel.setPageSize(pageSize);//设置每页显示记录数
        String hql = new StringBuffer().append("from ")//添加form字段
                .append(GenericsUtils.getGenericName(entityClass))//添加对象类型
                .append(" ")//添加空格
                .append(where == null ? "" : where)//如果where为null就添加空格,反之添加where
                .append(createOrderBy(orderby))//添加排序条件参数
                .toString();//转化为字符串
        Query query = getSession().createQuery(hql);//执行查询
        setQueryParams(query, queryParams);//为参数赋值
        List<T> list;//定义List对象
        // 如果maxResult<0，则查询所有
        if (pageSize < 0 && pageNo < 0) {
            list = query.list();//将查询结果转化为List对象
        } else {
            list = query.setFirstResult(getFirstResult(pageNo, pageSize))//设置分页起始位置
                    .setMaxResults(pageSize)//设置每页显示的记录数
                    .list();//将查询结果转化为List对象
            //定义查询总记录数的hql语句
            hql = new StringBuffer().append("select count(*) from ")//添加hql语句
                    .append(GenericsUtils.getGenericName(entityClass))//添加对象类型
                    .append(" ")//添加空格
                    .append(where == null ? "" : where)//如果where为null就添加空格,反之添加where
                    .toString();//转化为字符串
            query = getSession().createQuery(hql);//执行查询
            setQueryParams(query, queryParams);//设置hql参数
            int totalRecords = ((Long) query.uniqueResult()).intValue();//类型转换
            pageModel.setTotalRecords(totalRecords);//设置总记录数
        }
        pageModel.setList(list);//将查询的list对象放入实体对象中
        return pageModel;//返回分页的实体对象
    }

    @Transactional(propagation = Propagation.NOT_SUPPORTED, readOnly = true)
    public List<T> queryByCriteria(QueryEntity query, PageModel pageModel) {
        Criteria criteria = getSession().createCriteria(entityClass);
        //相等条件
        Iterator iterator = query.getEqParams().entrySet().iterator();
        while (iterator.hasNext()) {
            Map.Entry eqEntry = (Map.Entry) iterator.next();
            String key = (String) eqEntry.getKey();
            Object value = eqEntry.getValue();
            if (value != null) {
                criteria.add(Restrictions.eq(key, value));
            }
        }
        //like字符串条件
        iterator = query.getLikeStrings().entrySet().iterator();
        Disjunction dis = Restrictions.disjunction();
        while (iterator.hasNext()) {
            Map.Entry likeEntry = (Map.Entry) iterator.next();
            String key = (String) likeEntry.getKey();
            String value = (String) likeEntry.getValue();
            if (isValidateRealString(value)) {
                dis.add(Restrictions.like(key, "%" + value.trim() + "%"));
            }
        }
        criteria.add(dis);

        if (query.getBeginCreateTime() != null) {
            Timestamp beginCreateTime = new Timestamp(query.getBeginCreateTime().getTime());
            criteria.add(Restrictions.ge(query.getDateKeyword(), beginCreateTime));
        }
        if (query.getEndCreateTime() != null) {
            Timestamp endCreateTime = new Timestamp(query.getEndCreateTime().getTime());
            criteria.add(Restrictions.le(query.getDateKeyword(), endCreateTime));
        }
        //排序条件
        Map<String, String> orderBy = query.getOrderBy();
        if (orderBy != null && orderBy.size() > 0) {
            for (String key : orderBy.keySet()) {
                if (orderBy.get(key).equals("desc")) {
                    criteria.addOrder(Order.desc(key));
                } else if (orderBy.get(key).equals("asc")) {
                    criteria.addOrder(Order.asc(key));
                }
            }
        }
        if (pageModel.getPageSize() > 0 || pageModel.getPageNo() > 0) {
            int first = getFirstResult(pageModel.getPageNo(), pageModel.getPageSize());
            int maxResults = pageModel.getPageSize();
            pageModel.setTotalRecords(criteria.list().size());
            criteria.setFirstResult(first);
            criteria.setMaxResults(maxResults);
        }
        pageModel.setList(criteria.list());
        return pageModel.getList();
    }

    /**
     * 执行更新或删除
     *
     * @param hql
     * @return 更新或删除的数量
     */
    @Override
    public int executeHql(String hql) {
        Query query = getSession().createQuery(hql);
        return query.executeUpdate();
    }

    /**
     * 获取分页查询中结果集的起始位置
     *
     * @param pageNo   第几页
     * @param pageSize 页面显示的记录数
     * @return 起始位置
     */
    protected int getFirstResult(int pageNo, int pageSize) {
        int firstResult = (pageNo - 1) * pageSize;
        return firstResult < 0 ? 0 : firstResult;
    }

    /**
     * 对query中的参数赋值
     *
     * @param query
     * @param queryParams
     */
    protected void setQueryParams(Query query, Object[] queryParams) {
        if (queryParams != null && queryParams.length > 0) {
            for (int i = 0, k = 0; i < queryParams.length; i++) {
                if (queryParams[i] != null) {
                    query.setParameter(k, queryParams[i]);
                    k++;
                }
            }
        }
    }

    /**
     * 创建排序hql语句
     *
     * @param orderBy
     * @return 排序字符串
     */
    protected String createOrderBy(Map<String, String> orderBy) {
        StringBuffer sb = new StringBuffer("");
        if (orderBy != null && orderBy.size() > 0) {
            sb.append(" order by ");
            for (String key : orderBy.keySet()) {
                sb.append(key).append(" ").append(orderBy.get(key)).append(",");
            }
            sb.deleteCharAt(sb.length() - 1);
        }
        return sb.toString();
    }

    public boolean isValidateRealString(String... ids) {
        for (String s : ids) {
            if (s == null || s.equals("")) {
                return false;
            }
        }
        return true;
    }

}